package com.server.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author @追风少年
 * @description NIO Server
 * @date 2022/4/12
 */
public class NIOServer {

    /**
     * 参考图片<img src="https://gitee.com/xiaotianen/images/raw/master/img/image-20220412174856065.png" />
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        // 创建 serverSocketChannel -> ServerSocket
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 得到一个 selector 对象
        Selector selector = Selector.open();

        // 绑定一个端口，进行监听
        serverSocketChannel.socket().bind(new InetSocketAddress(8888));
        // 设置为非阻塞
        serverSocketChannel.configureBlocking(false);

        // 将 serverSocketChannel 注册到selector ,事件为 OP_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 循环等待客户端连接
        while (true) {
            // 等待一秒，如果没有事件发生，返回
            if (selector.select(1000) == 0) {
                System.out.println("服务器等待了1s,无连接");
                continue;
            }

            // 如果返回数据 > 0, 表示已经获取了对应的事件, 获取相关的selectionKey集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
            while (keyIterator.hasNext()) {
                SelectionKey selectionKey = keyIterator.next();

                // 根据 selectionKey ，对 对应的通道发生的事件做相应的处理
                if (selectionKey.isAcceptable()) {
                    // 如果是 OP_ACCEPT,代表有新的客户端连接
                    System.out.println("客户端连接成功！");
                    // 为该客户端生成一个 socketChannel
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("生成一个socketChannel, hashCode:" + socketChannel.hashCode());
                    // 将 socketChannel 设置为非阻塞
                    socketChannel.configureBlocking(false);
                    // 将 socketChannel 注册到 selector,绑定事件为 read，同时绑定Buffer
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));

                }

                if (selectionKey.isReadable()) {
                    // 读取数据
                    // 通过 selectionKey 反向获取对应的channel
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    // 获取channel关联的buffer
                    ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
                    // 从 buffer 中获取数据
                    socketChannel.read(byteBuffer);
                    System.out.println("获取到客户端传递的数据：" + new String(byteBuffer.array()));
                }

                // 移除当前的 selectionKey, 防止重复操作
                keyIterator.remove();
            }

        }

    }

}
